﻿
using AutoMapper;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using Microsoft.IdentityModel.Tokens;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using Workflow2211A.Application.DTO;
using Workflow2211A.Application.DTO.Inputs.Workflow;
using Workflow2211A.Application.DTO.Outputs.Workflow;
using Workflow2211A.Application.Steps;
using Workflow2211A.Domain;
using Workflow2211A.Domain.Entities;
using WorkflowCore.Interface;
using WorkflowCore.Models.DefinitionStorage.v1;
using WorkflowCore.Services.DefinitionStorage;
using Yitter.IdGenerator;

namespace Workflow2211A.Application.Services
{
    /// <summary>
    /// 服务实现
    /// </summary>
    public class WorkflowService : IWorkflowService
    {
        /// <summary>
        /// 加载流程定义的接口
        /// </summary>
        private readonly IDefinitionLoader _definitionLoader;
        /// <summary>
        /// 工作流注册表接口
        /// </summary>
        private readonly IWorkflowRegistry _workflowRegistry;
        //AutoMapper
        private readonly IMapper _mapper;
        //流程仓储
        IBaseRepository<WorkflowDefinitionModel> _definitionRepository;
        //流程主机
        private readonly IWorkflowHost _workflowHost;
        //审批仓储
        private readonly IBaseRepository<AuditsModel> _auditRepository;
        //Http上下文
        private readonly IHttpContextAccessor _contextAccessor;
        //流程实例仓储
        private readonly IBaseRepository<WorkflowInstanceModel> _instanceRepository;
        /// <summary>
        /// 当前登录人ID
        /// </summary>
        public long CurrentUserId { get; set; }
        /// <summary>
        /// 构造方法
        /// </summary>
        /// <param name="definitionLoader"></param>
        /// <param name="workflowRegistry"></param>
        /// <param name="mapper"></param>
        /// <param name="definitionRepository"></param>
        /// <param name="workflowHost"></param>
        /// <param name="auditRepository"></param>
        /// <param name="contextAccessor"></param>
        /// <param name="instanceRepository"></param>
        public WorkflowService(IDefinitionLoader definitionLoader,
            IWorkflowRegistry workflowRegistry,
            IMapper mapper,
            IBaseRepository<WorkflowDefinitionModel> definitionRepository,
            IWorkflowHost workflowHost,
            IBaseRepository<AuditsModel> auditRepository,
            IHttpContextAccessor contextAccessor,
            IBaseRepository<WorkflowInstanceModel> instanceRepository)
        {
            _definitionLoader = definitionLoader;
            _mapper = mapper;
            _definitionRepository = definitionRepository;
            _workflowHost = workflowHost;
            _auditRepository = auditRepository;
            _contextAccessor = contextAccessor;
            _instanceRepository = instanceRepository;
            _workflowRegistry = workflowRegistry;
        }

        /// <summary>
        /// 添加流程定义
        /// </summary>
        /// <param name="input">输入参数</param>
        /// <returns></returns>
        public APIResult<int> AddDefinition(DefinitionAddInput input)
        {
            CurrentUserId = Convert.ToInt64(_contextAccessor.HttpContext.User.FindFirstValue("UserId"));
            //讲流程定义添加到数据库中
            WorkflowDefinitionModel model = _mapper.Map<WorkflowDefinitionModel>(input);
            model.Id = YitIdHelper.NextId();
            model.Steps = JsonConvert.SerializeObject(input.Steps);
            model.CreateUserId = CurrentUserId;
            model.UpdateUserId = CurrentUserId;
            //model.FormTemplate = "{}";
            _definitionRepository.Add(model);
            LoadDefinition(model);

            return new APIResult<int>() { Code = ResultCode.Success, Data = 0, Message = "添加成功" };
        }

        /// <summary>
        /// 将数据库中的流程定义加载至流程引擎中
        /// </summary>
        /// <param name="model">实体</param>
        public void LoadDefinition(WorkflowDefinitionModel model)
        {
            /**
             * 1.判断是否已经注册流程
             * 2.创建流程定义对象
             * 3.添加开始步骤
             * 4.循环添加审批步骤（1）创建审批的步骤对象，（2）给审批步骤添加输入参数
             * 5.添加结束步骤
             * 6.调用IDefinitionLoader.LoadDefinition 加载至流程引擎中
             */
            //判断流程是否被注册
            if (_workflowRegistry.IsRegistered(model.DefinitionId, model.Version))
            {
                return;
            }
            
            //想办法把前端传过来的对象转化为引擎认识的流程定义对象
            DefinitionSourceV1 source = new()
            {
                Id = model.DefinitionId,
                Version = model.Version,
                Description = model.Title,
                //只有这样的写法才能通过反射找到
                //【完全限定名（Full Name）  程序集全名（Assembly Full Name）】
                DataType = $"{typeof(Dictionary<string, object>).FullName},{typeof(Dictionary<string, object>).Assembly.FullName}",

            };
            var steps = JsonConvert.DeserializeObject<List<StepNode>>(model.Steps);
            if (steps.Any())
            {
                //步骤对象
                StepSourceV1 startStep = new()
                {
                    Id = nameof(StartStep),
                    Name = "开始",
                    //节点类型
                    StepType = $"{typeof(StartStep).FullName},{typeof(StartStep).Assembly.FullName}",
                    NextStepId = steps.First().StepId//开始步骤指向的是审批步骤集合中的第一个步骤ID
                };
                source.Steps.Add(startStep);

                //添加要审批的步骤
                foreach (var step in steps)
                {
                    StepSourceV1 auditStep = new()
                    {
                        Id = step.StepId,
                        Name = step.StepName,
                        //节点类型
                        StepType = $"{typeof(AuditStep).FullName},{typeof(AuditStep).Assembly.FullName}",
                        NextStepId = step.NextStepId,
                    };
                    //设置步骤的输入参数
                    auditStep.Inputs.TryAdd("AuditUserId", $"\"{step.AuditUserId}\"");
                    auditStep.Inputs.TryAdd("AuditName", $"\"{step.AuditName}\"");

                    source.Steps.Add(auditStep);
                }

                StepSourceV1 endStep = new()
                {
                    Id = nameof(EndStep),
                    Name = "结束",
                    //节点类型
                    StepType = $"{typeof(EndStep).FullName},{typeof(EndStep).Assembly.FullName}",
                };
                source.Steps.Add(endStep);

                //将流程定义对象进行序列化
                var json = JsonConvert.SerializeObject(source);
                //将流程加载到引擎内存中（这个流程才能被发起）,相当于控制台中注册流程
                _definitionLoader.LoadDefinition(json, Deserializers.Json);
            }
            
           
        }
        /// <summary>
        /// 流程发起
        /// </summary>
        /// <param name="input">输入参数</param>
        /// <returns></returns>
        public async Task<APIResult<string>> StartWorkflow(WorkflowStartInput input)
        {
            CurrentUserId = Convert.ToInt64(_contextAccessor.HttpContext.User.FindFirstValue("UserId"));
            //判断是否有表单
            var definition = _definitionRepository.GetAll().AsNoTracking().FirstOrDefault(x=>x.DefinitionId==input.DefinitionId && x.Version == input.Version);
            if (string.IsNullOrWhiteSpace(definition.FormTemplate))
            {
                return new APIResult<string>
                {
                    Code = ResultCode.Success,
                    Data = "",
                    Message = "请先设计表单"
                };
            }
            //工作流实例启动，返回流程实例ID
            var workflowId = await _workflowHost.StartWorkflow(input.DefinitionId, input.Version);

            //添加业务流程实例
            var workflowInstance = new WorkflowInstanceModel
            {
                ApplicantUserName = input.ApplicantUserName,
                AuditUserId = "",
                AuditUserName = "",
                CreateUserId = CurrentUserId,
                UpdateUserId = CurrentUserId,
                DefinitionId = input.DefinitionId,
                FormData = input.FormData,
                Id = YitIdHelper.NextId(),
                Status = "发起",
                StepId = "",
                StepName = "",
                Title = input.Title,
                WorkflowId = workflowId,
            };
            _instanceRepository.Add(workflowInstance);

            return new APIResult<string>()
            {
                Code = ResultCode.Success,
                Data = workflowId,
                Message = "流程发起成功"
            };
        }

        /// <summary>
        /// 审批
        /// </summary>
        /// <param name="input">输入参数</param>
        /// <returns></returns>
        public async Task<APIResult<int>> Audit(AuditInput input)
        {

            CurrentUserId = Convert.ToInt64(_contextAccessor.HttpContext.User.FindFirstValue("UserId"));
            //1.判断是否有审批任务
            var audit = _auditRepository.GetAll().FirstOrDefault(x => x.WorkflowId == input.WorkflowId && !x.Status && x.AuditUserId == CurrentUserId);
            if (audit == null)
            {
                return new APIResult<int>()
                {
                    Code = ResultCode.Fail,
                    Data = 0,
                    Message = "暂无审批任务"
                };
            }
            //发布事件，触发流程
            await _workflowHost.PublishEvent("MyEvent", input.WorkflowId, input);

            //将代办设置为已审批
            audit.OprationType = input.OprationType;
            audit.Remark = input.Remark;
            audit.Status = true;
            audit.UpdateTime = DateTime.Now;
            _auditRepository.Update(audit);

            return new APIResult<int>()
            {
                Code = ResultCode.Success,
                Data = 1,
                Message = "审批成功"
            };
        }
        /// <summary>
        /// 添加代办
        /// </summary>
        /// <param name="audit"></param>
        /// <returns></returns>
        public int AddAudit(AuditAddInput audit)
        {
            //在后台任务中，是拿不到当前请求上下文
            //CurrentUserId = Convert.ToInt64(_contextAccessor.HttpContext.User.FindFirstValue("UserId"));
            var model = _mapper.Map<AuditsModel>(audit);
            model.Id = YitIdHelper.NextId();
            model.Status = false;
            model.Remark = "";
            model.OprationType = "";
            model.CreateUserId = audit.AuditUserId;
            model.UpdateUserId = audit.AuditUserId;

            return _auditRepository.Add(model);
        }

        /// <summary>
        /// 获取代办
        /// </summary>
        /// <returns></returns>
        public APIPageing<AuditOutput> GetTodoList(PageInput pageInput)
        {
            CurrentUserId = Convert.ToInt64(_contextAccessor.HttpContext.User.FindFirstValue("UserId"));
            var list = _auditRepository.GetAll().AsNoTracking()
                .Where(x => !x.Status && x.AuditUserId == CurrentUserId);

            var pageList = list.OrderByDescending(x => x.Id).Skip((pageInput.PageIndex - 1) * pageInput.PageSize).Take(pageInput.PageSize).ToList();
            return new APIPageing<AuditOutput>()
            {
                TotalCount = list.Count(),
                Code = ResultCode.Success,
                PageData = _mapper.Map<List<AuditOutput>>(pageList),
            };
        }
        /// <summary>
        /// 获取流程设计列表
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public APIPageing<WorkflowDefinitionOutput> GetDefinitions(PageInput input)
        {
            var query = _definitionRepository.GetAll().AsNoTracking();
            var pageList = query.OrderByDescending(x => x.Id).Skip((input.PageIndex - 1) * input.PageSize).Take(input.PageSize).ToList();

            var list = _mapper.Map<List<WorkflowDefinitionOutput>>(pageList);
            foreach (var item in pageList)
            {
                var steps = JsonConvert.DeserializeObject<List<StepNode>>(item.Steps);
                list.FirstOrDefault(x => x.Id == item.Id).StepCount = steps.Count();
            }
            return new APIPageing<WorkflowDefinitionOutput>()
            {
                PageCount = (int)Math.Ceiling(query.Count()*1.0/input.PageSize),
                TotalCount = query.Count(),
                Code = ResultCode.Success,
                PageData = list
            };
        }

        /// <summary>
        /// 查询流程实例
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public APIPageing<WorkflowInstanceOutput> GetWorkflows(WorkflowQueryInput input)
        {
            var query = _instanceRepository.GetAll().AsNoTracking();
            if (!string.IsNullOrEmpty(input.Title))
            {
                query = query.Where(x => x.Title.Contains(input.Title));
            }
            if (input.BeginTime != null && input.EndTime != null)
            {
                query = query.Where(x => x.CompleteTime >= input.BeginTime && x.CompleteTime <= input.EndTime);
            }

            var list = query.OrderByDescending(x => x.Id).Skip((input.PageIndex - 1) * input.PageSize).Take(input.PageSize).ToList();

            return new APIPageing<WorkflowInstanceOutput>
            {
                Code = ResultCode.Success,
                TotalCount = query.Count(),
                PageCount = (int)Math.Ceiling(query.Count() * 1.0 / input.PageSize),
                PageData = _mapper.Map<List<WorkflowInstanceOutput>>(list)
            };
        }

        /// <summary>
        /// 获取表单的详情
        /// </summary>
        /// <param name="workflowDefinitionId"></param>
        /// <returns></returns>
        public APIResult<FormTemplateDetail> GetFormTemplateDetail(long workflowDefinitionId)
        {
            var definition = _definitionRepository.GetAll().AsNoTracking().FirstOrDefault(x=>x.Id==workflowDefinitionId);
            if (string.IsNullOrWhiteSpace(definition.FormTemplate))
            {
                return new APIResult<FormTemplateDetail>
                {
                    Code = ResultCode.Fail,
                    Message = "请先设计表单",
                };
            }
            FormTemplateDetail result = new FormTemplateDetail
            {
                DefinitionId = definition.DefinitionId,
                Title = definition.Title,
                Version = definition.Version
            };
            //
            if (!string.IsNullOrWhiteSpace(definition.FormTemplate))
            {
                result.Templates = JsonConvert.DeserializeObject<List<FormTemplateModel>>(definition.FormTemplate)!;
            }
            return new APIResult<FormTemplateDetail>
            {
                Code = ResultCode.Success,
                Message = "表单详情查询成功",
                Data = result,
            };
        }
        /// <summary>
        /// 保存流程设计表单
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public APIResult<int> SaveFormTemplate(SaveFormTemplateInput input)
        {
            var definition = _definitionRepository.GetAll().FirstOrDefault(x=>x.Id==input.Id);
            //判断是否存在，存在则修改
            
            definition.FormTemplate = JsonConvert.SerializeObject(input.Templates);
            _definitionRepository.Update(definition);
            
            return new APIResult<int>
            {
                Code = ResultCode.Success,
                Message = "表单设计保存成功",
                Data =1
            };
        }

        /// <summary>
        /// 获取流程详情
        /// </summary>
        /// <param name="workflowId">流程实例Id</param>
        /// <returns></returns>
        public APIResult<WorkflowDetailOutput> GetWorkflowDetail(string workflowId)
        {
            WorkflowDetailOutput result = new();

            var instance = _instanceRepository.GetAll().AsNoTracking().FirstOrDefault(x=>x.WorkflowId == workflowId);
            result.WorkflowIntance = _mapper.Map<WorkflowInstanceOutput>(instance);
            result.FormData = instance.FormData;

            //获取审批记录
            var auditList = _auditRepository.GetAll().AsNoTracking().Where(x => x.WorkflowId == workflowId).ToList() ;
            result.AuditList = _mapper.Map<List<AuditOutput>>(auditList);

            return new APIResult<WorkflowDetailOutput>
            {
                Code = ResultCode.Success,
                Message = "请求成功",
                Data = result
            };
        }
    }
}
